commonization vs abstraction
ソフトウェア開発の現場では「抽象化」と「共通化」という言葉がしばしば混同して使われる。どちらもコードの整理や設計改善の文脈で登場するため無理もないが、両者は本質的に異なる概念である。この違いを意識しないまま設計判断を行うと、保守性の低いコードを生み出す原因になりかねない。
抽象化とは、詳細を隠蔽し本質だけを外部に公開する行為である。その目的は関心の分離にあり、呼び出し側が実装の詳細を知らなくても済む状態を作ることにある。インターフェースの定義やレイヤー構造の導入がその典型例だ。
一方、共通化は重複したコードを一箇所にまとめる行為である。DRY原則の文脈で語られることが多く、同じ処理を複数箇所に記述しないという動機に基づいている。
両者の決定的な違いは、共通化が必ずしも抽象化を伴わない点、そして抽象化が共通化を目的としない場合がある点にある。
たとえば、実装が一つしか存在しない場合でもインターフェースを定義することがある。テスタビリティの確保や依存関係逆転の原則を適用するためだ。これは抽象化ではあるが、共通化ではない。逆に、複数のクラスから同一のユーティリティメソッドを呼び出す場合、それは共通化ではあるが、必ずしも抽象化とは言えない。
実務において特に厄介なのは、共通化を名目とした過剰な抽象化である。たまたま現時点でコードが類似しているだけの二つの処理を無理に共通化すると、後に一方だけ仕様変更が発生した際に深刻な問題を引き起こす。本来異なる変更理由を持つものを一つにまとめてしまったことが原因である。
この観点から導かれる教訓がある。共通化の判断基準は「コードが似ているか」ではなく「変更理由が同じか」であるべきだということだ。変更理由が異なるコードは、たとえ今は同一に見えても、将来的には別々に進化する可能性が高い。この視点は、抽象化の適切な粒度を検討する際にも有効な指針となる。